package nl.dxn.tunnel.server.handel;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import nl.dxn.tunnel.enums.ProxyTypeEnum;
import nl.dxn.tunnel.enums.TransferMessageType;
import nl.dxn.tunnel.po.TransferMessage;
import nl.dxn.tunnel.server.Constants;
import nl.dxn.tunnel.server.cache.AgentChannelDto;
import nl.dxn.tunnel.server.cache.AgentChannelManager;
import nl.dxn.tunnel.server.config.TcpConfigProperties;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;

/**
 * 处理服务器接收到的外部请求
 */
public class ClientTcpHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(ClientTcpHandler.class);
    private final TcpConfigProperties tcpProperties;

    public ClientTcpHandler(TcpConfigProperties tcpProperties) {
        this.tcpProperties = tcpProperties;
    }

    /**
     * 连接初始化，建立连接
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        try {
            logger.info("{} 连接",ctx.channel().remoteAddress());
        } catch (Exception ex) {
            logger.error("", ex);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)  {
        try {
            AgentChannelDto proxy = ctx.channel().attr(Constants.PROXY).get();
            if (proxy == null) {
                logger.info("{} {} 创建链接",ctx.channel().remoteAddress(),tcpProperties.getServerId());
                ctx.channel().config().setAutoRead(false);
                proxy = AgentChannelManager.getTcpAgentChannel(tcpProperties.getServerId());

                if (proxy == null) {
                    ctx.channel().config().setAutoRead(true);
                    logger.info("tcp端口{} 对应的proxyId: {} ,没有注册代理", tcpProperties.getPort(), tcpProperties.getServerId());
                    ctx.channel().disconnect();
                    ctx.channel().flush();
                    ctx.close();
                    return;
                }
                ctx.channel().attr(Constants.PROXY).set(proxy);

                TransferMessage connectMessage = new TransferMessage();
                connectMessage.setType(TransferMessageType.TYPE_CONNECTED);
                connectMessage.getConfig().setServerId(tcpProperties.getServerId());
                connectMessage.getConfig().setChannelId(ctx.channel().id().asLongText());
                connectMessage.getConfig().setProxyType(ProxyTypeEnum.HTTP.code);

                Pair<String,TransferMessage> pair = AgentChannelManager.sendData(proxy.getChannel(),connectMessage);
                if(StringUtils.isNotBlank(pair.getKey())
                        || StringUtils.isNotBlank(pair.getRight().getConfig().getResult()))
                {
                    ctx.channel().config().setAutoRead(true);
                    logger.info("tcp端口{} 对应的proxyId: {} ,代理转发失败 {} {}"
                            , tcpProperties.getPort(), tcpProperties.getServerId(),pair.getKey(),pair.getRight().getConfig().getResult());
                    ctx.channel().disconnect();
                    ctx.channel().flush();
                    ctx.close();
                    return;
                }

                HashMap<String, Channel> clientMap = proxy.getChannel().attr(Constants.CLIENT_MAP).get();
                if(clientMap == null)
                {
                    clientMap = new HashMap<>();
                    proxy.getChannel().attr(Constants.CLIENT_MAP).set(clientMap);
                }
                clientMap.put(ctx.channel().id().asLongText(),ctx.channel());

                ctx.channel().config().setAutoRead(true);
            }

            ByteBuf readBuffer = (ByteBuf) msg;
            byte[] data = new byte[readBuffer.readableBytes()];
            readBuffer.readBytes(data);
            readBuffer.release();

            TransferMessage sendMessage = new TransferMessage();
            sendMessage.setType(TransferMessageType.TYPE_DATA);
            sendMessage.getConfig().setServerId(tcpProperties.getServerId());
            sendMessage.getConfig().setChannelId(ctx.channel().id().asLongText());
            sendMessage.getConfig().setProxyType(ProxyTypeEnum.TCP.code);
            sendMessage.setData(data);

            proxy.getChannel().writeAndFlush(sendMessage);
        } catch (Exception ex) {
            logger.error("", ex);
        }
//        finally {
//            ReferenceCountUtil.release(msg);
//        }
    }

    /**
     * 连接中断
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        try {
            logger.info("{} {} 断开连接",tcpProperties.getServerId(),ctx.channel().remoteAddress());

            AgentChannelDto proxy = ctx.channel().attr(Constants.PROXY).get();
            if (proxy == null) {
                ctx.close();
                return;
            }

            HashMap<String, Channel> clientMap  = proxy.getChannel().attr(Constants.CLIENT_MAP).get();

            if(clientMap != null)
            {
                clientMap.remove(ctx.channel().id().asLongText());
            }

            TransferMessage sendMessage = new TransferMessage();
            sendMessage.setType(TransferMessageType.TYPE_DISCONNECTED);
            sendMessage.getConfig().setChannelId(ctx.channel().id().asLongText());
            sendMessage.getConfig().setProxyType(ProxyTypeEnum.TCP.code);

            proxy.getChannel().writeAndFlush(sendMessage);



            ctx.close();
        } catch (Exception ex) {
            logger.error("", ex);
        }
    }

    /**
     * 连接异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("",cause);
        ctx.close();
    }
}
